#!/usr/bin/guile \
-e main -s
!#

;; This is a program that checks to see if a string of numbers has
;; repeatitive numbers...

;; use these modules to help my process the command line arguments.
(use-modules (ice-9 getopt-long))
(use-modules (ice-9 regex))

;; This function returns some repeating digits.  If its arguments
;; are "4444" and "4" it will return 4:3.  If its arguments are "4444"
;; and "44", it will return "44:1".
;; The procedure only returns repeating substrings of length "number".
;; So (doesANumberRepeat "123123" "2")  will return '()
;;  (doesANumberRepeat "123123" "3") will return '("123:1 ")
;;  (doesANumberRepeat "123123" "1" will return '("1:1 " "2:1 " "3:1 ")
;; It works by first the first repeating digit, then it recurses and removes
;; those repeating digits.
;; an example of finding out if a number repeats a single digit.
;; 123561236
;; string is longer than 2
;; 1 is the first digit and it repeats (cons recurse)
;; 2356236
;; string is longer than 2
;; 2 is the first digit and it repeats (cons recurse)
;; 35636
;; string is longer than 2
;; 3 is the first digit and it repeats (cons recurse)
;; 566
;; string is longer than 2
;; 5 is the first digit, but it does not repeat, recurse
;; 66
;; string is longer than 2
;; 6 is the first digit and repeats (cons recurse)
;; ""
;; (cons '())
;; TODO This algorithm fails! (doesANumberRepeat "123123" 2) -> '("12:1")
;; The correct answer is '("12:1 " "23:1 ")
;; scheme does allow for default values in functions...((lambda* (x #:optional (y 2) ) (display (number->string (+ x y)))) 1 2)
(define doesANumberRepeat
  (lambda* (string number #:optional (ssloc 0)) ;; ssloc -> substring location
    ;; If we are looking for a repeating substring that is longer than the string,
    ;; then stop looking for repeating digits.  As the function recurses the string gets shorter and shorter.
    ;; Eventually the string will be less than string.
    (let* ((digit (getDigit string number))     ;; digit is the first number characters of the string
           (repeat (repetitions digit string))) ;; repeat is how many times digit repeats in the string.
      (display (string-append " We are recursing (cons " digit ":" (number->string repeat) " )" "\n"))
      ;; if the number repeats in the string, say "1" repeats twice in "11", then store that.
      (if (< 0 repeat)
          (begin
            (cons
             (string-append digit ":" (number->string repeat) " ")
             ;; recurse, but remove the repeating digits that you've already found.
             ;; so (doesANumberRepeat "1122" "1") will eventually call (doesANumberRepeat "22" "1")
             (doesANumberRepeat  number)))
          ;; if the specified digit/s does not repeat, recurse and remove those digit/s from the string.
          (doesANumberRepeat number)))))

;; This function takes a number in a string
;; number is (ceiling (/ (string-length string) 2))
;; Here's an example of how it works.
;; (wNR "1230123445544550666777666777" 14)
;;   list is '()
;;   (wNR "1230123445544550666777666777" 13)
;;     list is '()
;;     (wNR "1230123445544550666777666777" 12)
;;       ...
;;       (wNR "1230123445544550666777666777" 3)
;;         list is '("666:1 " "777:1 ")
;;       (wNR "1230123445544550666777666777" 2)
;;         list is '("44:1 " "55:1 ")
;;           (wNR "1230123445544550666777666777" 1)
;;             list is '("1:1 " "2:1 " "3:1" "0:1 ")
;;               (wNR "" 0)
(define (whichNumbersRepeat string number)
  (let* ((number (1- number))
         ;; at some point number will be 0;
         ;; but (doesANumberRepeat "123123" 0) creates an infinite loop.
         ;; So if number == 0, then set list to '().
         (list (if (> number 0)
                   (doesANumberRepeat string number)
                   '())))
    (if (> 0 number)
        '()
        (if (null? list)
            (whichNumbersRepeat string number)
            (cons list (whichNumbersRepeat string number))))))

;; (whichNumbersRepeat "11" (ceiling (/ (string-length "11") 2)))

;; This function is defunct.  The algorithm that uses it fails.
;; I can probably remove it.
;; dR 12301237556655668 8
;; string is longer than 8, 12301237 does not repeat
;; dR 556655668 8
;; string is longer than 8, 55665566 does not repeat.
;; dR 8
;; string is less than 8.
;; (stripNumberFromString "5" "5523")  -->  "23"
(define (stripNumberFromString number string)
  (regexp-substitute/global #f number string 'pre "" 'post))

;; returns the digit at the specified location and length
(define (getDigit string number)
  (substring string 0 number))

;; How Many Times Does the number (substring) Repeat?
;; "4" repeats 2 times in "444".
;; "44" repeats once in "44044".
(define (repetitions sstr str)
  (1- (length (list-matches sstr str))))

(define (displayListOfLists list)
  (if (null? list)
      (begin
        (display "'()\n"))
      (begin
        (display (string-append (apply string-append (car list))))
        (displayListOfLists (cdr list)))))

(define (main args)
  ;;the option specification tells getopt-long how
  ;; to parse the command line
  (let* ((option-spec '((version (single-char #\v) (value #f))
                        (help    (single-char #\h) (value #f))
                        (number  (single-char #\n) (value #t)
                                 ;; (required #t)
                                 )))
         ;; tell getopt-long to parse the command line and put the
         ;; data in options
         (options (getopt-long args option-spec))
         ;; was  --help or -h used?
         (help-wanted (option-ref options 'help #f))
         (version-wanted (option-ref options 'version #f))
         ;; was -c or --calc used?  If there was no value given,
         ;; then return #f
         (number-wanted (option-ref options 'number #f)))
    (if (or version-wanted help-wanted)
        (begin
          (if version-wanted
              (display "repeat version 0.1\n"))
          (if help-wanted
              (begin
                (display "repeat [options]\n")
                (display "-v  --version  Display version\n")
                (display "-h, --help     Display this help info\n")
                (display "-n, --number   Does this number repeat?\n")
                )))
        (display (string-append  (apply string-append (doesANumberRepeat number-wanted 2)) "\n")))))
